/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 *
 *           File:  test.cpp
 *    Description:  Вычисление вероятности ошибки для различных кодов
 *    				заданных в конфигурационном файле
 *
 *         Author:  Aleksey Golovchenko (lexgolovchenko@gmail.com)
 *        Created:  20.03.2013 17:33:11
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <cmath>
extern "C" {
	#include <quadmath.h>
}

#include <iostream>
#include <fstream>
#include <cstdio>
#include <string>
#include <vector>

#include <libconfig.h++>

#include "error_probability.h"


/*
 * Диапазон значений вероятности битовой ошибки
 */
__float128 PIN_MIN;
__float128 PIN_MAX;
__float128 PIN_STEP;

// N = K + 2*t, для кода Рида-Соломона
const int *K_t[2];
std::vector<int> N;
std::vector<int> K;
std::vector<int> t;

/*
 * Имя файла для записи результатов
 */
std::string output_file(int N, int K, int t) {
	std::string res;
	res.resize(20);
	std::sprintf(&res[0], "res_%d_%d_%d.txt", N, K, t);

	return res;
}

char outerr_buf[128];
char pin_buf[128];

/*
 * Чтение конфигурационного файла
 */
int read_config(const char *cfgfile) {

	try {
		libconfig::Config cfg;
		cfg.readFile(cfgfile);

		double buf;
		if (!cfg.lookupValue("conf.pin_min", buf)) {
			goto ERROR;
		}
		PIN_MIN = buf;

		if (!cfg.lookupValue("conf.pin_max", buf)) {
			goto ERROR;
		}
		PIN_MAX = buf;

		if (!cfg.lookupValue("conf.pin_step", buf)) {
			goto ERROR;
		}
		PIN_STEP = buf;

		/*
		 * Массив N
		 */
		libconfig::Setting &Nset = cfg.lookup("conf.N");
		if (!Nset.isArray()) {
			goto ERROR;
		}

		N.resize(Nset.getLength());
		for (int i = 0; i < Nset.getLength(); ++i) {
			N[i] = Nset[i];
		}

		/*
		 * Массив K
		 */
		libconfig::Setting &Kset = cfg.lookup("conf.K");
		if (!Kset.isArray()) {
			goto ERROR;
		}

		if (Kset.getLength() != N.size()) {
			goto ERROR;
		}

		K.resize(Kset.getLength());
		for (int i = 0; i < Kset.getLength(); ++i) {
			K[i] = Kset[i];
		}

		/*
		 * Массив t
		 */
		t.resize(N.size());
		for (int  i = 0; i < N.size(); ++i) {
			if (N[i] < K[i] || N[i] < 0 || K[i] < 0) {
				goto ERROR;
			}
			t[i] = (N[i] - K[i]) / 2;
		}


	}
	catch (libconfig::ConfigException &e) {
		std::cerr << "*** ERROR *** : config exception - " << e.what() << std::endl;
		goto ERROR;
	}

	return 0;
ERROR:
	return -1;
}

int test_start(const char *cfg) {

	if (-1 == read_config(cfg)) {
		std::cerr << "*** ERROR *** : read config file error!" << std::endl;
		goto ERROR;
	}

	/*
	 * Вычисление значений выходных вероятностей ошибки для различных
	 * параметров, запись результатов в файлы
	 */
	for (std::size_t i = 0; i < N.size(); ++i) {

		const int &Ki = K[i];
		const int &ti = t[i];
		const int &Ni = N[i];

		std::fstream fout;
		fout.open(output_file(Ni, Ki, ti).c_str(), std::ios::out);
		if (!fout.is_open() || fout.fail()) {
			std::cerr << "*** ERROR *** : can not open file " << output_file(Ni, Ki, ti) << std::endl;
			goto ERROR;
		}

		__float128 pin = PIN_MIN;
		do {
			quadmath_snprintf(outerr_buf, sizeof outerr_buf, "%-#*.8Qe", 2, code_out_perr(pin, Ni, ti));
			quadmath_snprintf(pin_buf, sizeof pin_buf, "%-#*.8Qe", 20, pin);
			fout << pin_buf << " " << outerr_buf << std::endl;

			pin += PIN_STEP;
		} while (pin < PIN_MAX);

		pin = PIN_MAX;
		quadmath_snprintf(outerr_buf, sizeof outerr_buf, "%-#*.8Qe", 2, code_out_perr(pin, Ni, ti));
		quadmath_snprintf(pin_buf, sizeof pin_buf, "%-#*.8Qe", 20, pin);
		fout << pin_buf << " " << outerr_buf << std::endl;

		fout.close();
	}

	return 0;
ERROR:
	return -1;

}
